<!--
 * @Date: 2025-01-02 16:50:03
 * @Author: LiSong
 * @LastEditors: LiSong
 * @LastEditTime: 2025-02-25 15:21:08
 * @Description: 表单设计抽屉组件
-->
<template>
  <el-drawer ref="drawerRef"
    :="drawerAttrs"
    v-model="drawerState.visible">
    <div class="fp-design-drawer-wrapper">
      <div class="design-drawer-head">
        <div class="header-title">
          {{ formState.baseInfo.name }}
        </div>
        <div class="header-steps">
          <el-steps simple :active="stepState.stepActive" finish-status="success">
            <el-step title="基本配置" />
            <el-step title="内容设计" />
            <el-step title="内容预览" />
          </el-steps>
        </div>
        <div class="header-tools">
          <el-button @click="handlePrevStep()" :disabled="stepState.stepActive <= stepState.ksStep">上一步</el-button>
          <el-button @click="handleNextStep()" :disabled="stepState.stepActive >= stepState.jsStep">下一步</el-button>
          <el-button type="primary" :disabled="saveDisable" @click="handleSave">保存</el-button>
          <el-button type="danger" @click="handleClose">关闭</el-button>
        </div>
      </div>
      <div class="design-drawer-body">
        <template v-if="stepState.stepActive === 0">
          <div class="base-info-panel">
            <el-form
              ref="baseFormRef"
              :="baseFormAttrs"
              :model="formState.baseInfo"
              :rules="baseFormRules"
            >
              <el-form-item label="名称" prop="name">
                <el-input v-model="formState.baseInfo.name" />
              </el-form-item>
              <el-form-item label="编码" prop="code">
                <el-input v-model="formState.baseInfo.code" />
              </el-form-item>
              <el-form-item label="类型" prop="formTypeName">
                <el-input readonly v-model="formState.baseInfo.formTypeName" />
              </el-form-item>
              <el-form-item label="排序" prop="orderNum">
                <el-input-number style="width: 100%;" v-model="formState.baseInfo.orderNum" />
              </el-form-item>
              <el-form-item label="描述" prop="remark">
                <el-input v-model="formState.baseInfo.remark" type="textarea" :autosize="{ minRows: 10, maxRows: 12 }" />
              </el-form-item>
            </el-form>
          </div>
        </template>
        <FpDesigner
          v-if="stepState.stepActive === 1"
          v-loading="drawerState.designLoading"
          element-loading-text="加载中..."
          ref="fpDesignRef"
          :formJson="formState.formJson"
          @loaded="() => drawerState.designLoading = false"
        />
        <FpRender
          v-if="stepState.stepActive === 2"
          v-loading="drawerState.renderLoading"
          element-loading-text="加载中..."
          ref="fpRenderRef"
          formType="view"
          :formJson="formState.formJson"
          :slotJson="formState.slotJson"
          :disabled="true"
          @loaded="() => drawerState.renderLoading = false"
        />
      </div>
    </div>
  </el-drawer>
</template>

<script setup>
import { defAxios } from '@/utils/http';
import { reactive, ref, toRaw } from 'vue';

import { ElLoading, ElMessage, ElMessageBox } from 'element-plus';
import { FpRender, FpDesigner, FormUtils, FormPojo } from '@fp'
import * as PressUtils from '@/utils/press.js'

const emits = defineEmits(['success'])

// 抽屉组件的Ref
const drawerRef = ref()
// 表单渲染组件的Ref
const fpRenderRef = ref(null)
// 表单设计组件的Ref
const fpDesignRef = ref(null)

// 默认数据
const defInfo = FormPojo.baseInfo
// 表单数据集
const formState = reactive({
  baseInfo: JSON.parse(JSON.stringify(defInfo)),
  formJson: {},
  slotJson: {},
  formFileds: [],
})

// 抽屉的数据集
const drawerState = reactive({
  mode: 'add',
  visible: false,
  designLoading: false,
  renderLoading: false,
})
// 抽屉组件的属性定义
const drawerAttrs = reactive({
  size: '100%',
  class: 'fp-design-drawer',
  zIndex: 2000,
  showClose: false,
  withHeader: false,
  appendToBody: true,
  closeOnPressEscape: false,
})
/**
 * 新增操作
 */
const handleAdd = async (info) => {
  drawerState.visible = true
  // 设置模式
  drawerState.mode = 'add'
  // 合并基本信息
  mergeBaseData(info)
}
/**
 * 编辑操作
 */
const handleEdit = async (info) => {
  drawerState.visible = true
  const loadService = ElLoading.service({ fullscreen: true, text: '加载中......' })
  // 设置模式
  drawerState.mode = 'edit'
  // 获取设计器数据
  const data = await reqGetDesignInfo(info.formId)
  // 设置设计器数据
  const { prdFormContent } = data
  if (prdFormContent && prdFormContent.structureJson) {
    try {
      const { structureJson } = prdFormContent
      // 是否为压缩数据
      if (PressUtils.isPressData(structureJson)) {
        formState.formJson = PressUtils.decompressData(structureJson)
      } else {
        formState.formJson = JSON.parse(structureJson)
      }
      formState.slotJson = JSON.parse(prdFormContent.slotJson)
    } catch (error) {
      console.error('解析表单数据失败', error)
    }
  }
  // 合并基本信息
  mergeBaseData({ ...data, ...prdFormContent || {} }, info)
  loadService.close()
}
/**
 * 打开抽屉
 * 
 * @param info 参数
 */
const handleOpen = (info) => {
  if (!info.formId) {
    handleAdd(info)
  } else {
    handleEdit(info)
  }
}
/**
 * 保存数据
 */
const handleSave = async () => {
  if (stepState.stepActive === 1) {
    let flag = setDesignData()
    if (!flag) return
  }
  // 封装保存的数据
  const prdFormContent = {
    slotJson: JSON.stringify(formState.slotJson),
    submitURL: '',
    structureJson: PressUtils.compressData(formState.formJson),
    validateContent: ''
  }
  const submitDesignData = {
    ...formState.baseInfo,
    prdFormContent,
    prdFormFieldBo: toRaw(formState.formFileds)
  }
  const loadService = ElLoading.service({ fullscreen: true, text: '保存中......' });
  const flag = await reqSaveDesignInfo(submitDesignData)
  loadService.close()
  if (!flag) return
  emits('success', submitDesignData)
  if (stepState.stepActive <= 1) return
  handleReset()
  drawerState.visible = false
}
/**
 * 重置数据
 */
const handleReset = () => {
  // 重置表单校验
  if (baseFormRef.value) baseFormRef.value.resetFields()
  // 重置基本信息
  formState.baseInfo = JSON.parse(JSON.stringify(defInfo))
  formState.slotJson = {}
  formState.formJson = {}
  // 重置步骤数
  stepState.stepActive = stepState.ksStep
  // 清除缓存
  FormUtils.clearFormDesignerCache()
}
/**
 * 关闭抽屉
 */
const handleClose = () => {
  ElMessageBox.confirm(
    '关闭后所有未保存的数据将会清空，请谨慎操作！',
    '提示',
    {
      type: 'warning',
      showClose: false,
      customStyle: {
        'margin-top': '120px',
        'vertical-align': 'top',
      },
      closeOnClickModal: true
    }
  ).then(() => {
    drawerState.visible = false
    handleReset()
  }).catch(() => {
  })
}

/**
 * 合并基本信息
 * @param {Object} data 需要合并的数据
 * @param {Object} info 需要合并的数据
 */
const mergeBaseData = (data, row = {}) => {
  Object.keys(defInfo).forEach(key => {
    formState.baseInfo[key] = data[key] || row[key] || defInfo[key]
  })
}
/**
 * 获取设计数据，并赋值到formState中
 * 
 * @returns {Boolean} 是否成功获取数据
 */
const setDesignData = () => {
  // 获取设计数据
  const designData = fpDesignRef.value.getDesignData()
  if (!designData) {
    ElMessage.warning('请先进行内容设计！')
    return false
  }
  // 数据赋值
  formState.formJson = designData.formJson
  formState.slotJson = designData.slotJson
  formState.formFileds = designData.formFileds
  return true
}

// 步骤条组件的数据集
const stepState = reactive({
  ksStep: 0,
  jsStep: 2,
  stepActive: 0,
})
// 保存按钮是否禁用
const saveDisable = computed(() => {
  if (drawerState.mode === 'add') {
    return !(stepState.stepActive >= 1)
  } else {
    return !(stepState.stepActive >= 0)
  }
})
/**
 * 上一步操作
 */
const handlePrevStep = () => {
  if (stepState.stepActive-- < 1) stepState.stepActive = stepState.ksStep;
  switch (stepState.stepActive) {
    case 1:
      drawerState.designLoading = true
      break;
    default:
      break;
  }
}
/**
 * 下一步操作
 */
const handleNextStep = async () => {
  let nextGo = false
  switch (stepState.stepActive) {
    case 0:
      nextGo = await validateBaseForm()
      drawerState.designLoading = nextGo
      break;
    case 1:
      nextGo = setDesignData()
      drawerState.renderLoading = nextGo
      break;
    case 2:
      break;
    default:
      break;
  }
  if (!nextGo) return
  if (stepState.stepActive++ > stepState.jsStep) stepState.stepActive = stepState.ksStep;
}

// 表单组件的Ref
const baseFormRef = ref(null)
// 表单组件的属性定义
const baseFormAttrs = reactive({
  labelWidth: 'auto'
})
// 表单字段校验规则
const baseFormRules = reactive({
  name: [
    { required: true, message: '请输入名称', trigger: 'blur' }
  ],
  code: [
    { required: true, message: '请输入编码', trigger: 'blur' }
  ],
  formType: [
    { required: true, message: '请输入类型', trigger: 'blur' }
  ],
  orderNum: [
    { required: false, message: '请输入排序', trigger: 'blur' }
  ],
  // formTypeName: [
  //   { required: true, message: '请输入类型', trigger: 'blur' }
  // ],
})
/**
 * 校验基础信息表单
 */
const validateBaseForm = async () => {
  return new Promise((resolve, reject) => {
    baseFormRef.value.validate((valid) => {
      if (valid) {
        resolve(true)
      } else {
        resolve(false)
      }
    })
  })
}


// 抽屉中请求API
const drawerApis = {
  /**
   * 根据表达ID获取表单信息
   * 
   * @param formId 表单ID
   */
  reqGetFormInfo: (formId) => {
    return defAxios({
      url: '/prdFormInfo/queryPrdFormInfoListByFormId',
      method: 'GET',
      params: { formId }
    })
  },
  /**
   * 保存表单信息
   */
  reqSaveFormInfo: (params) => {
    return defAxios({
      url: '/prdFormInfo/addPrdFormInfo',
      method: 'POST',
      data: params,
    });
  },
}

/**
 * 获取设计数据
 * 
 * @param id 唯一ID
 */
const reqGetDesignInfo = (id) => {
  return new Promise((resolve) => {
    drawerApis.reqGetFormInfo(id).then(res => {
      if (res.code === 200) {
        resolve(res.data)
      } else {
        resolve({});
        console.error(res.msg)
      }
    }).catch(err => {
      resolve({});
      console.error('获取配置数据失败', err)
    })
  })
}
/**
 * 保存设计数据
 * 
 * @param params 参数
 */
const reqSaveDesignInfo = (params) => {
  return new Promise((resolve, reject) => {
    drawerApis.reqSaveFormInfo(params).then(res => {
      if (res.code === 200) {
        ElMessage.success('保存成功！')
        resolve(true)
      } else {
        ElMessage.error(res.msg);
        resolve(false)
      }
    }).catch(error => {
      console.error(error);
      resolve(false)
    })
  })
}

defineExpose({
  handleAdd,
  handleEdit,
  handleOpen,
})

</script>

<style lang="scss" scoped>
.fp-design-drawer {
	&-wrapper {
		height: 100%;
		display: flex;
		flex-direction: column;
		justify-content: space-between;
	}
}
.design-drawer-head {
	display: flex;
	width: 100%;
	padding: 0 8px;
	height: 50px;
	line-height: 50px;
	align-items: center;
	border-bottom: 1px solid #d9d9d9;
	background-color: #fff;
	.header-title {
		width: 300px;
		font-size: 16px;
	}
	.header-steps {
		flex: 1;
		line-height: 1;
		padding: 15px 120px 15px 30px;
		.el-steps {
			padding: 0;
			background-color: #fff;
		}
	}
	.header-tools {
		// width: 330px;
		text-align: right;
	}
}
.design-drawer-body {
	flex: 1;
	overflow: auto;
	min-height: 100px;
}
.base-info-panel {
	width: 50%;
	margin: 0 auto;
	margin-top: 30px;
}
:deep(.el-step.is-simple .el-step__icon) {
	width: 20px;
	height: 20px;
	display: flex;
	align-items: center;
}
:deep(.el-step__icon-inner) {
	font-size: 22px !important;
}
</style>
